﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using JetBrains.Annotations;

namespace com.susi.util {
    public static class StringExtensions {
        /// <summary>
        ///     对string数组中所有string运行trim并返回自己（会改变数组内的值）
        /// </summary>
        public static string[] TrimAll(this string[] strary)
        {
            if (strary == null) return null;
            for (var i = 0; i < strary.Length; i++) strary[i] = strary[i].Trim();
            return strary;
        }

        public static string[] DeleteAllNullOrEmpty(this string[] strary)
        {
            return strary.Where(v => !v.IsNullOrEmpty()).ToArray();
        }

        public static string[] DeleteAllNullOrWhiteSpace(this string[] strary)
        {
            return strary.Where(v => !v.IsNullOrWhiteSpace()).ToArray();
        }

        /// <summary>
        ///     对string数组中所有string删除空白并返回自己（会改变数组内的值）
        ///     <para>删除空白后如果是""，不会设置其为null，null元素返回null</para>
        ///     <para>空白字符为[ \f\n\r\t\v]</para>
        /// </summary>
        public static string[] ReplaceAllSpace(this string[] strary)
        {
            if (strary == null) return null;
            for (var i = 0; i < strary.Length; i++) strary[i] = strary[i].Replace(new[] {" ", "\f", "\n", "\r", "\t", "\v"}, "");
            return strary;
        }

        /// <summary>
        ///     删除所有空白字符并返回
        ///     <para>删除空白后如果是""，保留""，null元素返回null</para>
        ///     <para>空白字符为[ \f\n\r\t\v]</para>
        /// </summary>
        [CanBeNull]
        public static string ReplaceAllSpace([CanBeNull] this string str)
        {
            if (str == null) return null;
            return str.Replace(new[] {" ", "\f", "\n", "\r", "\t", "\v"}, "");
        }

        /// <summary>
        ///     遍历替换oldstr，结果可能包含""，null(str是null的情况下)，如果参数集合中包含null则会从replace中引发异常
        ///     <para>old值和new值应一一对应</para>
        ///     <para>TODO 优化GC</para>
        /// </summary>
        public static string Replace(this string str, IEnumerable<string> oldstr, IEnumerable<string> newstr)
        {
            if (str.IsNullOrEmpty()) return str;
            var itor    = oldstr.GetEnumerator();
            var newitor = newstr.GetEnumerator();
            while (itor.MoveNext()) {
                var newerstr = newitor.MoveNext() ? newitor.Current : "";
                str = str.Replace(itor.Current, newerstr);
            }

            itor.Dispose();
            newitor.Dispose();
            return str;
        }

        /// <summary>
        ///     遍历替换oldchar，结果可能包含""，null(str是null的情况下)，如果参数集合中包含null则会从replace中引发异常
        ///     <para>old值和new值应一一对应</para>
        ///     <para>TODO 优化GC</para>
        /// </summary>
        public static string Replace(this string str, IEnumerable<char> oldchar, IEnumerable<char> newchar)
        {
            if (str.IsNullOrEmpty()) return str;
            var itor    = oldchar.GetEnumerator();
            var newitor = newchar.GetEnumerator();
            while (itor.MoveNext())
                if (newitor.MoveNext())
                    str  = str.Replace(itor.Current, newitor.Current);
                else str = str.Remove(itor.Current);
            itor.Dispose();
            newitor.Dispose();
            return str;
        }

        /// <summary>
        ///     遍历替换oldchar，结果可能包含""，null(str是null的情况下)，如果参数集合中包含null则会从replace中引发异常
        ///     <para>TODO 优化GC</para>
        /// </summary>
        public static string Replace(this string str, IEnumerable<char> oldchar, string newstr)
        {
            if (str.IsNullOrEmpty()) return str;
            var sb = new StringBuilder();
            foreach (var chr in str)
                // ReSharper disable once PossibleMultipleEnumeration
                if (oldchar.Contains(chr)) sb.Append(newstr);
                else sb.Append(chr);
            return sb.ToString();
        }

        /// <summary>
        ///     遍历替换oldstr，结果可能包含""，null(str是null的情况下)，如果参数集合中包含null则会从replace中引发异常
        ///     <para>TODO 优化GC</para>
        /// </summary>
        public static string Replace(this string str, IEnumerable<string> oldstr, string newstr)
        {
            if (str.IsNullOrEmpty()) return str;
            var itor                    = oldstr.GetEnumerator();
            while (itor.MoveNext()) str = str.Replace(itor.Current, newstr);
            itor.Dispose();
            return str;
        }

        /// <summary>
        ///     遍历替换oldchar，结果可能包含""，null(str是null的情况下)，如果参数集合中包含null则会从replace中引发异常
        ///     <para>TODO 优化GC</para>
        /// </summary>
        public static string Replace(this string str, IEnumerable<char> oldchar, char newstr)
        {
            if (str.IsNullOrEmpty()) return str;
            var itor                    = oldchar.GetEnumerator();
            while (itor.MoveNext()) str = str.Replace(itor.Current, newstr);
            itor.Dispose();
            return str;
        }

        public static string ReplaceByRegex(this string str, string pattern, string value)
        {
            return Regex.Replace(str, pattern, value);
        }

        public static string ReplaceByRegex(this string str, Regex regex, MatchEvaluator evaluator)
        {
            return regex.Replace(str, evaluator);
        }

        public static bool IsNullOrEmpty(this string str)
        {
            return string.IsNullOrEmpty(str);
        }

        public static bool IsNullOrWhiteSpace(this string str)
        {
            return string.IsNullOrWhiteSpace(str);
        }

        /// <summary>
        ///     尝试创建正侧表达式，失败返回null，不会抛异常
        ///     <para>纯空白字符的regex总是返回null</para>
        /// </summary>
        public static Regex CreatRegex(this string regex)
        {
            try {
                return new Regex(regex);
            }
            catch {
                return null;
            }
        }

        /// <summary>
        ///     尝试创建正侧表达式，失败返回null，不会抛异常
        ///     <para>纯空白字符的regex总是返回null</para>
        /// </summary>
        public static Regex CreatRegex(this string regex, RegexOptions op)
        {
            try {
                return new Regex(regex, op);
            }
            catch {
                return null;
            }
        }

        /// <summary>
        ///     见
        ///     <see cref="Path.Combine(string,string)" />，另外会对\号转成/号
        /// </summary>
        public static string PathCombine(this string patha, string pathb)
        {
            return Path.Combine(patha, pathb).Replace("\\", "/");
        }

        /// <summary>
        ///     <see cref="Path.GetFileName(string)" />的包装形式
        /// </summary>
        public static string GetPathFileName(this string path)
        {
            return Path.GetFileName(path);
        }

        /// <summary>
        ///     <see cref="Path.GetDirectoryName(string)" />的包装形式
        /// </summary>
        public static string GetPathDir(this string path)
        {
            return Path.GetDirectoryName(path);
        }

        /// <summary>
        ///     调用<see cref="Regex.IsMatch(string, string, RegexOptions)" />验证,op=
        ///     <see cref="RegexOptions.CultureInvariant" />
        /// </summary>
        public static bool IsMatch(this string input, string pattern)
        {
            return Regex.IsMatch(input, pattern, RegexOptions.CultureInvariant);
        }

        /// <summary>
        ///     调用regex验证
        /// </summary>
        public static bool IsMatch([NotNull] this string input, Regex regex)
        {
            return regex.IsMatch(input);
        }

        public static string RemoveFromStart([NotNull] this string content, int count)
        {
            return content.Remove(0, count);
        }

        /// <param name="content">原型</param>
        /// <param name="count">特指该字符串参数的长度</param>
        public static string RemoveFromStart([NotNull] this string content, [NotNull] string count)
        {
            return content.Remove(0, count.Length);
        }

        public static string RemoveFromEnd([NotNull] this string content, int count)
        {
            return content.Remove(content.Length - count, count);
        }

        /// <param name="content">原型</param>
        /// <param name="count">特指该字符串参数的长度</param>
        public static string RemoveFromEnd([NotNull] this string content, [NotNull] string count)
        {
            return RemoveFromEnd(content, count.Length);
        }

        [NotNull]
        public static string ToBase64([NotNull] this string name)
        {
            var bytes = Encoding.UTF8.GetBytes(name);
            return Convert.ToBase64String(bytes);
        }

        /// <summary>
        /// 将目标中文名字转换成符合^[a-zA-Z][a-zA-Z0-9]*$的susiASCII名字
        /// <para>注意不要把整段文字放进来，只支持单独的中文名字转换</para>
        /// </summary>
        /// <exception cref="ArgumentNullException">arg can't be NullOrWhiteSpace</exception>
        /// <exception cref="ArgumentException">can not covert from '__'</exception>
        /// <exception cref="ArgumentException">not match ^[\u4e00-\u9fa5_a-zA-Z0-9]+$</exception>
        [Obsolete]
        public static string ToSusiASCIIName(this string utfName)
        {
            if (utfName.IsNullOrWhiteSpace()) throw new ArgumentNullException(nameof(utfName));
            if (utfName.Contains("__")) throw new ArgumentException("can not covert from '__' ");
            const string chk = "^[\u4e00-\u9fa5_a-zA-Z0-9]+$";
            if (!utfName.IsMatch(chk)) throw new ArgumentException($"{utfName} not match {chk}");
            return FromASCIIString(utfName).Replace("\\", "__");
        }

        /// <summary>
        /// 支持代码段
        /// </summary>
        [Obsolete]
        public static string FromSusiASCIIname(this string susiASCIIname)
        {
            var str = susiASCIIname.Replace("__", "\\");
            return ToASCIIString(str);
        }

        public static string FromASCIIString(this string value)
        {
            StringBuilder sb = new StringBuilder();
            foreach (char c in value) {
                if (c > 127) {
                    // This character is too big for ASCII
                    sb.Append("\\u");
                    sb.Append(((int) c).ToString("x4"));
                }
                else {
                    sb.Append(c);
                }
            }

            return sb.ToString();
        }

        public static string ToASCIIString(this string value)
        {
            string localEvaluator(Match m)
            {
                var gpv = m.Value.RemoveFromStart(@"\u");
                return ((char) int.Parse(gpv, NumberStyles.HexNumber)).ToString();
            }

            return Regex.Replace(
                value,
                @"\\u[a-zA-Z0-9]{4}",
                localEvaluator);
        }

        /// <summary>
        /// 将字符串转换成^[_a-zA-Z0-9]$且以_i开头的SusiBase64字符串 
        /// </summary>
        [NotNull]
        public static string ToSusiBase64([NotNull] this string str)
        {
            var base64 = str.ToBase64();
            return $"_i{base64.Replace("+", "_p").Replace("/", "_s").Replace("=", "_e")}";
        }

        /// <summary>
        /// 将SusiBase64字符串转还原
        /// </summary>
        [NotNull]
        public static string FromSusiBase64([NotNull] this string str)
        {
            return str.RemoveFromStart("_i")
                      .Replace("_p", "+")
                      .Replace("_s", "/")
                      .Replace("_e", "=")
                      .FromBase64();
        }

        [NotNull]
        public static string FromBase64([NotNull] this string str)
        {
            var bytes = Convert.FromBase64String(str);
            return Encoding.UTF8.GetString(bytes);
        }
    }
}